package com.llc.mall.auth.domain.user.service.impl;

import com.llc.mall.auth.domain.user.entity.User;
import com.llc.mall.auth.domain.user.repository.UserRepository;
import com.llc.mall.auth.domain.user.service.UserDomainService;
import com.llc.mall.auth.infrastructure.constant.AuthAccountStatusEnum;
import com.llc.mall.common.core.exception.Mall4cloudException;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

import java.util.Objects;

@Slf4j
@Service
public class UserDomainServiceImpl implements UserDomainService {

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Resource
    private UserRepository userRepository;


    public static final String USER_NOT_FOUND_SECRET = "USER_NOT_FOUND_SECRET";

    private static String userNotFoundEncodedPassword;

    @Override
    public User authenticate(String userName, String password) {
        User user = userRepository.findUserByName(userName);
        if (Objects.isNull(user)) {
            prepareTimingAttackProtection();
            // 再次进行运算，防止计时攻击
            mitigateAgainstTimingAttack(password);
            throw new Mall4cloudException("用户名或密码不正确!");
        }

        if (Objects.equals(user.getStatus(), AuthAccountStatusEnum.DISABLE.value())) {
            throw new Mall4cloudException("用户已禁用，请联系客服!");
        }

        if (!passwordEncoder.matches(password, user.getPassword())) {
            throw new Mall4cloudException("用户名或密码不正确!");
        }
        return user;
    }

    /**
     * 防止计时攻击
     */
    private void prepareTimingAttackProtection() {
        if (userNotFoundEncodedPassword == null) {
            userNotFoundEncodedPassword = this.passwordEncoder.encode(USER_NOT_FOUND_SECRET);
        }
    }

    /**
     * 防止计时攻击
     */
    private void mitigateAgainstTimingAttack(String presentedPassword) {
        if (presentedPassword != null) {
            this.passwordEncoder.matches(presentedPassword, userNotFoundEncodedPassword);
        }
    }
}
